import * as d3 from 'd3'
export class ParallelChart {
    divId = ''
    data = []
    chart = {}
    dimensions = []
    itemsName = []
    color = d3.scaleOrdinal(d3.schemeCategory10)
    xScale = d3.scalePoint()
    yScale = {}

    constructor (divId) {
      this.divId = divId
    }

    draw () {
      this.initChart()
      this.initAxis()
      this.drawLabel()
      this.drawLegend()
      this.drawLines()
    }

    initChart () {
      this.chart.padding = {
        left: 50,
        right: 10,
        top: 50,
        bottom: 20
      }
      this.chart.divHeight = document.getElementById(this.divId).offsetHeight -
          this.chart.padding.top -
          this.chart.padding.bottom
      this.chart.divWidth = document.getElementById(this.divId).offsetWidth -
          this.chart.padding.left -
          this.chart.padding.right

      this.chart.svg = d3
        .select('#' + this.divId)
        .append('svg')
        .attr('width', this.chart.divWidth +
            this.chart.padding.left +
            this.chart.padding.right
        )
        .attr('height', this.chart.divHeight +
            this.chart.padding.top +
            this.chart.padding.bottom
        )
        .attr('class', 'svg_chart')
    }

    initAxis () {
      let divHeight = this.chart.divHeight

      this.xScale.domain(this.dimensions)
        .range([this.chart.padding.left, this.chart.divWidth], 1)

      this.dimensions.forEach(d => {
        this.yScale[d] = d3.scaleLinear()
          .domain([0, d3.max(this.data, p => {
            return +p[d]
          })])
          .range([this.chart.divHeight, this.chart.padding.top])
      })

      let yScale = this.yScale

      let gaxis = this.chart.svg.selectAll('.axis')
        .data(this.dimensions)
        .enter()
        .append('g')
        .attr('class', 'axis')
        .attr('transform', d => 'translate(' + this.xScale(d) + ', 0)')

      gaxis.append('g')
        .each(function (d) {
          d3.select(this).call(d3.axisLeft(yScale[d]).ticks(7))
        })

      let top = this.chart.padding.top
      let svg = this.chart.svg
      gaxis.append('g')
        .attr('id', d => 'brush-' + d)
        .attr('class', 'brush')
        .each(function (d) {
          d3.select(this).call(
            d3.brushY()
              .extent([
                [-10, top],
                [10, divHeight]
              ])
              .on('end', d => {
                brushEnd(d)
              })
          )
        })

      function brushEnd () {
        let brushs = svg.selectAll('.brush')._groups[0]
        let extents = []
        for (let i = 0; i < brushs.length; ++i) {
          extents.push(d3.brushSelection(brushs[i]))
        }
        svg.selectAll('.path')
          .style('opacity', d => {
            let flag = true
            brushs.forEach((p, i) => {
              let name = p.getAttribute('id').split('-')[1]
              if (extents[i] === null) {
                flag = flag && true
              } else if (extents[i][0] <= yScale[name](d[name]) && yScale[name](d[name]) <= extents[i][1]) {
                flag = flag && true
              } else flag = flag && false
            })
            if (flag === true) {
              return 0.8
            } else return 0.1
          })
      }
    }

    drawLines () {
      let xScale = this.xScale
      let yScale = this.yScale
      let xDomain = this.dimensions
      let t = d3.transition()
        .duration(1000)
        .ease(d3.easeLinear)
      let line = d3.line().curve(d3.curveBasis)
      let paths = this.chart.svg.append('g')
        .attr('class', 'background')
        .selectAll('path')
        .data(this.data)

      let pathEnter = paths.enter()
        .append('path')
        .attr('class', 'path')
        .attr('d', path)
        .style('stroke', (d, i) => d.color)
        .style('stroke-width', 1)
        .style('fill', 'none')
        .style('opacity', 0.8)
        .style('stroke-dasharray', function (d) {
          return this.getTotalLength()
        })
        .style('stroke-dashoffset', function (d) {
          return this.getTotalLength()
        })

      let pathUpdate = pathEnter.merge(paths)

      pathUpdate.transition(t)
        .style('stroke-dashoffset', 0)

      paths.exit()
        .transition()
        .duration(750)
        .style('stroke-dashoffset', function (d) {
          return this.getTotalLength()
        })
        .remove()

      function path (d) {
        return line(xDomain.map(function (p) {
          return [xScale(p), yScale[p](d[p])]
        }))
      }
    }

    drawLabel () {
      this.chart.svg.selectAll('.label')
        .data(this.dimensions)
        .enter()
        .append('text')
        .attr('x', d => this.xScale(d))
        .attr('y', this.chart.padding.top)
        .attr('dy', -5)
        .style('text-anchor', 'middle')
        .style('font-size', 10)
        .text(String)
    }

    drawLegend () {
      this.data.forEach(d => {
        if (this.itemsName.indexOf(d.category) === -1) {
          this.itemsName.push(d.category)
        }
      })
      let legendWidth = 15
      let legendHeight = 15
      let legends = this.chart.svg
        .selectAll('.legend')
        .data(this.itemsName)
      let legendEnter = legends.enter()
        .append('g')
        .attr('class', 'legend')

      legendEnter.append('rect')
        .attr('x', this.chart.divWidth + 5)
        .attr('y', (d, i) => this.chart.padding.top + legendHeight * i)
        .attr('width', 0)
        .attr('height', legendHeight - 5)
        .style('fill', (d, i) => this.color(i))

      legendEnter.append('text')
        .attr('x', this.chart.divWidth + legendWidth * 1.3 + 5)
        .attr('y', (d, i) => this.chart.padding.top + legendHeight * i + legendHeight / 2)
        .text(String)
        .style('font-size', 1e-6)

      let legendUpdate = legendEnter.merge(legends)

      legendUpdate.select('rect')
        .transition()
        .duration(750)
        .attr('width', legendWidth)

      legendUpdate.select('text')
        .transition()
        .duration(750)
        .style('font-size', 10)

      let legendExit = legends.exit()
        .transition()
        .duration(750)
        .remove()

      legendExit.select('rect')
        .attr('width', 0)

      legendExit.select('text')
        .style('stroke-opacity', 1e-6)
    }
}
